package com.yc.xunlei;

import com.yc.url.Test2_url_urlconnection_httpurlconnection;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author zwei
 * @create 2024-07-20 16:16
 */
public class Xunlei {
    private static Logger logger = Logger.getLogger(Test2_url_urlconnection_httpurlconnection.class);
    //private static volatile long fileSizeDownLoaded=0;  //不能保证long原子性
    private static long fileSizeDownLoaded = 0;
    //private static AtomicLong fileSizeDownLoaded=new AtomicLong(0); //保证原子性

    public static void main(String[] args) throws IOException, InterruptedException {
//        String url= "http://dldir1.qq.com/qqfile/qq/QQNT/Windows/QQ_9.9.12_240715_x64_01.exe";
        String url = "http://www.hostbuf.com/downloads/finalshell_install.exe";
        List<Thread> list = new ArrayList<>();
        //1.获取要下载的文件大小
        long filesize = getDownloadFileSize(url);
        logger.info("待下载的文件的大小：" + filesize);     //1951 9329 6                    --》1951 9329 6


        //2.新文件保存的位置
        String newFileName = genFileName(url);
        logger.info("下载后的文件名为：" + newFileName);
        String userhome = System.getProperty("user.home");
        String downloadPath = userhome + File.separator + newFileName;
        logger.info("下载后的文件路径为：" + downloadPath);


        //3.创建此新文件(空)
        RandomAccessFile raf = new RandomAccessFile(downloadPath, "rw");
        raf.setLength(filesize);
        raf.close();
        logger.info("空的新文件创建成功。。。");

        //4.获取本机线程数
        int threads = Runtime.getRuntime().availableProcessors();
        logger.info("本机线程数：" + threads);


        //5.计算每个线程下载的大小
        long sizePerThread = getSizePerThread(filesize, threads);
        logger.info("每个线程下载的大小：" + sizePerThread);

        long start = System.currentTimeMillis();
        //6.创建线程数组
        for (int i = 0; i < threads; i++) {
            DownLoadedSizeNotify dlsn = new DownLoadedSizeNotify() {
                @Override
                public void notifySize(long size) {
                    //方案1       耗时：100763毫秒     文件大小：74476309
//                    fileSizeDownLoaded+=size;     //不能保证原子性
//                    System.out.println("当前文件下载进度："+fileSizeDownLoaded);
                    //方案2       耗时：78669毫秒
                    synchronized (Xunlei.class) {    //Xunlei在jvm中只有一个class对象  即只有一把锁
                        fileSizeDownLoaded += size;
                        System.out.println("\r"+"当前文件下载进度：" + fileSizeDownLoaded);
                    }
                    //方案3           耗时： 82929毫秒
//                    fileSizeDownLoaded.addAndGet(size);
//                    System.out.println("当前文件下载进度："+fileSizeDownLoaded);
                }
            };
            DownLoadTask task = new DownLoadTask(i, filesize, threads, sizePerThread, url, downloadPath, dlsn);
            Thread thread = new Thread(task);
            thread.start();
            list.add(thread);
        }

        for (Thread t : list) {
            t.join();
        }
        long end = System.currentTimeMillis();
        System.out.println("下载完成，耗时：" + (end - start) + "毫秒");
    }

    /**
     * 计算每个线程要下载的字节数
     *
     * @param filesize
     * @param threads
     * @return
     */
    private static long getSizePerThread(long filesize, int threads) {
        return filesize % threads == 0 ? filesize / threads : filesize / threads + 1;
    }

    /**
     * 根据日期和时间生成新的文件的文件名
     *
     * @param url
     * @return
     */
    private static String genFileName(String url) {
        Date d = new Date();
        DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSS");
        String prefix = df.format(d);
        String suffix = url.substring(url.lastIndexOf("."));
        return prefix + suffix;
    }

    /**
     * 正式下载前  获取文件大小  HEAD
     *
     * @param url
     * @return
     * @throws IOException
     */
    private static long getDownloadFileSize(String url) throws IOException {
        long fileSize = 0;
        URL u = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) u.openConnection();
        //设置请求头
        connection.setRequestMethod("HEAD");
        connection.setConnectTimeout(3000);
        connection.connect();
        fileSize = connection.getContentLength();
        logger.info("文件大小" + fileSize);
        return fileSize;
    }

}

interface DownLoadedSizeNotify {
    public void notifySize(long size);
}
